package com.lost.octopus.es.helper.entity.wrapper;

import com.lost.octopus.es.helper.entity.model.FieldConfig;
import com.lost.octopus.es.helper.util.ArrayUtil;
import com.lost.octopus.es.helper.constant.EsSearchMode;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;

import javax.annotation.Resource;

import lombok.extern.log4j.Log4j2;

/**
 * 多值查询
 * 值兼容：字符串逗号隔开；数组类型
 * 支持两种模式：should和must模式
 *  <p>{@link EsSearchMode#SEARCH_SHOULD}</p> 用于普通字段，匹配值在列表中
 *
 * 如 and ( x=val1 or x=val2 or x=val3)
 * 如查询 类型在 1或者2或者3的的数据
 * <br/>
 * 注解：{@code @EsSearch(queryType = EsQueryMultiplyValWrapper.class, fieldName = "name")}
 * <br/>
 * 示例：{@code "1,张三"或者new String[]{"1", "张三"}}
 * <br/>
 * 效果：{@code {"bool":{"should":[{"term":{"name":{"value":"1"}}},{"term":{"name":{"value":"张三"}}}]}} }
 *  <p>{@link EsSearchMode#SEARCH_MUST}</p> 多用于字段为数组类型，可以查询多个值相等
 *
 *  如：and x=val1 and x=val2 and x=val3  因为es存储数组格式，如果x=[val1,val2,val3...]都可匹配到
 * 注解：{@code @EsSearch(queryType = EsQueryMultiplyValWrapper.class, fieldName = "name",searchMode=EsSearchMode.SEARCH_MUST)}
 * <br/>
 * 示例：{@code "1,张三"或者new String[]{"1", "张三"}}
 * <br/>
 * 效果：{@code {"bool":{"must":[{"term":{"name":{"value":"1"}}},{"term":{"name":{"value":"张三"}}}]}} }
 * @author zhangbh
 **/
@Log4j2
@Component
public class EsQueryMultiplyValWrapper extends AbstractQueryWrapper {

    @Resource
    private EsQueryWrapper esQueryWrapper;

    @Override
    public QueryBuilder addWrapper(BoolQueryBuilder builder, FieldConfig field) {

        Object value = field.getValue();
        // 校验是数组后，直接用工具转换
        List<Object> values = ArrayUtil.transList(value);

        if (CollectionUtils.isEmpty(values)) {
            return null;
        }

        EsSearchMode mode = getMode(field);
        log.info("多值查询模式={}", mode);

        BoolQueryBuilder must = QueryBuilders.boolQuery();

        if (values.size() == 1) {
            log.info("单个查询,value={},直接使用EsQueryWrapper", values.get(0));
            FieldConfig copy = field.copy();
            copy.setValue(values.get(0));
            // in查询中，只有一个值直接使用must
            copy.setSearchMode(EsSearchMode.SEARCH_MUST);
            return esQueryWrapper.addWrapper(builder, copy);
        }
        // 直接拼接
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        values.forEach(nowVal -> {
            QueryBuilder search = useBuilder(field.copy().setValue(nowVal));
            useMode(query, search, mode);
        });
        builder.must(query);
        return must;
    }

    @Override
    protected EsSearchMode defaultMode() {
        return EsSearchMode.SEARCH_SHOULD;
    }
}
